package com.ihr360.binlog.dao.impl;

import com.ihr360.binlog.dao.SyncedBasicStaffInfoDao;
import com.ihr360.binlog.datasource.JdbcTemplateHolder;
import com.ihr360.commons.exception.Ihr360RuntimeException;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.shared.basicstaffinfo.dto.SyncedBasicStaffInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Repository
public class SyncedBasicStaffInfoDaoImpl implements SyncedBasicStaffInfoDao {
    final Logger logger = LoggerFactory.getLogger(SyncedBasicStaffInfoDao.class.getName());
    private final static String INSERT_OR_UPDATE = "INSERT INTO sc_synced_basic_staff_info " +
            "(id, companyId, departmentId, departmentName, idCardNo, idCardType, mobileNo, sex, staffName,enrollInDate,lastWorkDay, staffStatus,positionName,positionId,staffNo) " +
            "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?,?) " +
            "on DUPLICATE key update departmentId=?, departmentName=?, idCardNo=?, idCardType=?, mobileNo=?, sex=?, staffName=?,enrollInDate=?,lastWorkDay=?, staffStatus=?,positionName=?,positionId=?,staffNo=?";

    private final static String DELETE_BY_ID = "DELETE from sc_synced_basic_staff_info where id=?";
    @Autowired
    JdbcTemplateHolder jdbcTemplateHolder;

    @Override
    public int update(List<SyncedBasicStaffInfo> syncedBasicStaffInfo) {
        if (CollectionUtils.isEmpty(syncedBasicStaffInfo)) {
            return 0;
        }
        List<Object[]> list = syncedBasicStaffInfo.stream().map(info -> {
            Object[] args = new Object[28];
            int index = 0;
            args[index++] = info.getId();
            args[index++] = info.getCompanyId();
            args[index++] = info.getDepartmentId();
            args[index++] = info.getDepartmentName();
            args[index++] = info.getIdCardNo();
            args[index++] = info.getIdCardType();
            args[index++] = info.getMobileNo();
            args[index++] = info.getSex();
            args[index++] = info.getStaffName();
            args[index++] = info.getEnrollInDate();
            args[index++] = info.getLastWorkDay();
            args[index++] = info.getStaffStatus().name();
            args[index++] = info.getPositionName();
            args[index++] = info.getPositionId();
            args[index++] = info.getStaffNo();

            args[index++] = info.getDepartmentId();
            args[index++] = info.getDepartmentName();
            args[index++] = info.getIdCardNo();
            args[index++] = info.getIdCardType();
            args[index++] = info.getMobileNo();
            args[index++] = info.getSex();
            args[index++] = info.getStaffName();
            args[index++] = info.getEnrollInDate();
            args[index++] = info.getLastWorkDay();
            args[index++] = info.getStaffStatus().name();
            args[index++] = info.getPositionName();
            args[index++] = info.getPositionId();
            args[index++] = info.getStaffNo();
            return args;
        }).collect(Collectors.toList());
        jdbcTemplateHolder.templates().stream().forEach(jdbc -> {
            try {
                Connection con = jdbc.getDataSource().getConnection();

                execute(con, new String[]{INSERT_OR_UPDATE}, list);

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw new RuntimeException(e.getMessage());
            }

        });
        return 1;
    }

    @Override
    public int delete(String id) {
        List<Object[]> list = new ArrayList<>(1);
        Object[] args = new Object[1];
        args[0] = id;
        list.add(args);
        jdbcTemplateHolder.templates().stream().forEach(jdbc -> {
            try {
                Connection con = jdbc.getDataSource().getConnection();
                execute(con, new String[]{DELETE_BY_ID}, list);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw new RuntimeException(e.getMessage());
            }
        });
        return 1;
    }

    @Override
    public int delete(SyncedBasicStaffInfo info) {
        return delete(info.getId());
    }

    @Override
    public int delete(List<SyncedBasicStaffInfo> syncedBasicStaffInfo) {
        if (CollectionUtils.isEmpty(syncedBasicStaffInfo)) {
            return 0;
        }
        List<Object[]> list = syncedBasicStaffInfo.stream().map(info -> {
            Object[] args = new Object[1];
            int index = 0;
            args[index++] = info.getId();
            return args;
        }).collect(Collectors.toList());
        jdbcTemplateHolder.templates().stream().forEach(jdbc ->
                {
                    try {
                        Connection con = jdbc.getDataSource().getConnection();
                        con.setAutoCommit(false);
                        execute(con, new String[]{DELETE_BY_ID}, list);
                        con.commit();
                        con.setAutoCommit(true);
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        throw new RuntimeException(e.getMessage());
                    }
                }
        );
        return 1;
    }

    private void execute(Connection conn, String[] sql, List<Object[]> args) throws Exception {
        conn.setAutoCommit(false);
        int currentSqlIndex = 0;
        try {
            int batchSize = 0;
            int commitSize = 1000; // number of rows you want to commit per batch.
            try {
                PreparedStatement ps = null;
                if (sql.length == 1) {
                    ps = conn.prepareStatement(sql[0]);
                }
                for (Object[] objects : args) {
                    if (sql.length > 1) {
                        String currentSql = sql[currentSqlIndex];
                        ps = conn.prepareStatement(currentSql);
                    }
                    //logger.log(Level.INFO,"----"+objects.length);
                    if (objects != null) {
                        for (int index = 0; index < objects.length; index++) {
                            Object obj = objects[index];
                            //logger.log(Level.INFO,"----"+index+" value:"+obj);
                            ps.setObject(index + 1, obj);
                        }
                    }
                    ps.executeUpdate();
                    batchSize++;
                    if (batchSize % commitSize == 0) {
                        conn.commit();
                    }
                    currentSqlIndex++;
                }
            } catch (Exception e) {
                e.printStackTrace();
                conn.rollback();
                throw new Ihr360RuntimeException(e.getMessage());
            } finally {
                conn.commit(); // commit the last batch of records
                conn.setAutoCommit(true);
                if (conn != null) {
                    conn.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(sql[currentSqlIndex]);
            if (args != null) {
                for (Object arg : args.get(currentSqlIndex)) {
                    if (arg != null) {
                        logger.info(arg.toString());
                    } else {
                        logger.info(null);
                    }
                }
            }
            conn.rollback();
            throw new Ihr360RuntimeException(e.getMessage());
        }

    }
}